package com.platform.common.config.shiro;

import com.platform.common.redis.RedisUtil;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Shiro Cache
 * 
 * @author LiangMingHui
 *
 * @param <K>
 * @param <V>
 */
public class ShiroCache<K, V> implements Cache<K, V> {

	private static final Logger logger = LoggerFactory.getLogger(ShiroCache.class);

	private static final int EXPIRE_TIME = 1800000;

	private String keyPrefix = "SHIRO_CACHE:";

	public ShiroCache(String keyPrefix) {
		this.keyPrefix = keyPrefix;
	}

	private String getCacheKey(K key) {
		return this.keyPrefix + key.toString();
	}

	@Override
	public V get(K key) throws CacheException {
		try {
			if (key == null) {
				logger.error("Key cann't be empty.....");
				return null;
			} else {
				@SuppressWarnings("unchecked")
				V value = (V) RedisUtil.getInstance().getObject(this.getCacheKey(key));
				return value;
			}
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public V put(K key, V value) throws CacheException {
		try {
			RedisUtil.getInstance().setObject(this.getCacheKey(key), value, EXPIRE_TIME);
			return value;
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public V remove(K key) throws CacheException {
		try {
			V previous = this.get(key);
			RedisUtil.getInstance().expire(this.getCacheKey(key), 0);
			return previous;
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public void clear() throws CacheException {

	}

	@Override
	public int size() {
		return 0;
	}

	@Override
	@SuppressWarnings("unchecked")
	public Set<K> keys() {
		List<K> listObj = (List<K>) RedisUtil.getInstance().keysObject(keyPrefix + "*");
		return new HashSet<K>(listObj);
	}

	@Override
	public Collection<V> values() {
		Set<K> keys = keys();
		if (!CollectionUtils.isEmpty(keys)) {
			List<V> values = new ArrayList<V>(keys.size());
			keys.stream().filter(e -> null != e).forEach(e -> values.add(get(e)));
			return Collections.unmodifiableList(values);
		} else {
			return Collections.emptyList();
		}
	}
}